#include "rrraytracing.h"
#include "rrmath.h"
#include "cmath"
#include "SDL_endian.h"
#include "rrprim.h"

RRRayTracing::RRRayTracing()
{
    //Set Screen Position
    s_h = 2.0f;
}

void RRRayTracing::rrGenerateEye(float xs, float ys)
{
    eye.rrGenerateEye(RRSetVec3(xs, ys, s_h));
}

void RRRayTracing::rrTrace(Uint32 *bufp, SDL_Surface *screen)
{
    RRPrim sp, pl;
    float dis1, dis2;
    pl.rrSetYPlane(10.0f);
    sp.rrSetSphere(0.0f, 5.0f, 15.0f, 13.0f);
    dis1 = sp.rrGetDistance(eye);
    dis2 = pl.rrGetDistance(eye);
    if((dis1 > 0.0f && dis1 <= dis2) || (dis1 > 0.0f && dis2 < 0.0f)) {
        Uint32 color;
        RRVec3 c;
        //c = rrTraceSphere(0.0f, 0.0f, 15.0f, 13.0f);
        c = sp.rrGetColor(lig);
            color = SDL_MapRGB(screen->format, 255 * c.x, 255 * c.y, 255 * c.z);
        *bufp = color;
    }
    else if((dis2 > 0.0f && dis2 < dis1) || (dis2 > 0.0f && dis1 < 0.0f)) {
        Uint32 color;
        RRVec3 c;
        c = pl.rrGetColor(lig);
        color = SDL_MapRGB(screen->format, 255 * c.x, 255 * c.y, 255 * c.z);
        *bufp = color;
    }
}

RRVec3 RRRayTracing::rrTraceSphere(float xc, float yc, float zc, float r)
{
    RRVec3 l_coord;
    l_coord = lig.rrGetLightCoord();
    RRVec3 e_coord;
    RRVec3 e_dir;
    e_coord = eye.rrGetEyeCoord();
    e_dir = eye.rrGetEyeDir();
    RRVec3 Pc;
    RRVec3 temp;
    RRVec3 Ret;
    Pc.x = xc; Pc.y = yc; Pc.z = zc;
    float A, B, C, D;
    A = RRInnerProduct(e_dir, e_dir);
    temp.x = e_coord.x - Pc.x;
    temp.y = e_coord.y - Pc.y;
    temp.z = e_coord.z - Pc.z;
    B = RRInnerProduct(e_dir, temp);
    C = RRInnerProduct(temp, temp) - r * r;
    D = B * B - A * C;
    //printf("%f %f %f %f\n", A, B, C, D);
    if(D > 0) {
        float t;
        t = (-B - sqrtf(D)) / A;
        //交点の位置
        RRVec3 P;
        P.x = e_coord.x + e_dir.x * t;
        P.y = e_coord.y + e_dir.y * t;
        P.z = e_coord.z + e_dir.z * t;
        //法線ベクトル
        RRVec3 N;
        N.x = P.x - Pc.x;
        N.y = P.y - Pc.y;
        N.z = P.z - Pc.z;
        N = RRNormalize(N);
        //光源へのベクトル
        RRVec3 L;
        L = RRSetVec3(l_coord.x - P.x, l_coord.y - P.y, l_coord.z - P.z);
        L = RRNormalize(L);
        //拡散反射強度
        A = RRInnerProduct(N, L);
        //光源からの反射ベクトル
        RRVec3 R;
        R = RRSetVec3(2 * A * N.x - L.x, 2 * A * N.y - L.y, 2 * A * N.z - L.z);
        R = RRNormalize(R);
        //視線方向へのベクトル
        RRVec3 V;
        V = RRSetVec3(-e_dir.x * t, -e_dir.y * t, -e_dir.z * t);
        V = RRNormalize(V);
        //鏡面反射強度
        B = RRInnerProduct(R, V);
        if(B < 0) B = 0.0f;
        B = powf(B, 10.0f);

        if(A < 0) A = 0.0f;

        Ret = RRSetVec3(B, B, B + A * 0.8f);
        RRClampVec3(&Ret, 0.0f, 1.0f);
        return Ret;
    }
    Ret = RRSetVec3(0.0f, 0.f, 0.0f);
    return Ret;
}

void RRRayTracing::rrSetLight(float x, float y, float z)
{
    lig.rrSetLightCoord(RRSetVec3(x, y, z));
}
